package com.gulimall.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.gulimall.product.vo.IndexCatalogVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.utils.PageUtils;
import com.common.utils.Query;

import com.gulimall.product.dao.CategoryDao;
import com.gulimall.product.entity.CategoryEntity;
import com.gulimall.product.service.CategoryService;

import javax.annotation.Resource;

@Slf4j
@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    private CategoryDao categoryDao;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<>()
        );

        return new PageUtils(page);
    }

    @Cacheable(value = "category" ,key= "'queryTreeList'")
    @Override
    public List<CategoryEntity> queryTreeList() {
        List<CategoryEntity> categoryList = baseMapper.selectList(null);
        categoryList.stream().filter(categoryEntity -> categoryEntity.getCatLevel() == 1)
                .sorted(Comparator.comparing(sort-> (sort.getSort() == null? 0 : sort.getSort())))
                .forEach(categoryEntity -> categoryEntity.setChildren(setChildList(categoryEntity,categoryList)));
        return categoryList;
    }

    @Override
    public Long[] getFatherIds(Long cateLogId) {
        List<Long> fatherIdList = new ArrayList<>();
        fatherIdList.add(cateLogId);
        getFatherIds(cateLogId, fatherIdList);
        Collections.reverse(fatherIdList);
        return fatherIdList.toArray(new Long[0]);
    }

    /**
     * 获取所有二级三级分类实体类
     * @return
     */
    @Cacheable(value = "category", key = "#root.method.name")
    @Override
    public Map<Long, List<IndexCatalogVo>> getIndexCatalog() {
//        String catalogJson = stringRedisTemplate.opsForValue().get("indexCatalogList");
//        if(StringUtils.isNotBlank(catalogJson)){
            // 如果缓存中存在，那么直接返回
//            Map<Long, List<IndexCatalogVo>> catalogList = JSON.parseObject(catalogJson, new TypeReference<Map<Long, List<IndexCatalogVo>>>(){});
//            return catalogList;
//        }else{
            // 不存在就去查询，然后向缓存中添加
            Map<Long, List<IndexCatalogVo>> indexCatalogFromDB = getIndexCatalogFromDB();
//            stringRedisTemplate.opsForValue().set("indexCatalogList",JSON.toJSONString(indexCatalogFromDB));
            return indexCatalogFromDB;
//        }
    }


    private Map<Long, List<IndexCatalogVo>> getIndexCatalogFromDB() {
        List<CategoryEntity> categoryList = categoryDao.selectList(null);
        // 找出一级分类集合
        List<CategoryEntity> firstLevelList = categoryList.stream().filter(categoryEntity -> categoryEntity.getCatLevel().equals(1)).collect(Collectors.toList());

        // 对一级分类进行处理，封装成需要的最终数据
        Map<Long, List<IndexCatalogVo>> indexCatalogVoMap = firstLevelList.stream().collect(Collectors.toMap(CategoryEntity::getCatId, level1Category -> {
            // 找出当前分类下的所有二级分类集合
            List<CategoryEntity> level2CategoryList = categoryList.stream().filter(categoryEntity2 -> categoryEntity2.getParentCid().equals(level1Category.getCatId())).collect(Collectors.toList());
            // 遍历二级
            List<IndexCatalogVo> IndexCatalogVoList = new ArrayList<>();
            for (CategoryEntity level2Category : level2CategoryList) {
                IndexCatalogVo indexCatalogVo = new IndexCatalogVo();
                indexCatalogVo.setCatalogId(level1Category.getCatId());
                indexCatalogVo.setId(level2Category.getCatId());
                indexCatalogVo.setName(level2Category.getName());

                // 寻找当前二级分类下的所有三级分类
                List<CategoryEntity> level3CategoryList = categoryList.stream().filter(categoryEntity3 -> categoryEntity3.getParentCid().equals(level2Category.getCatId())).collect(Collectors.toList());
                // 遍历所有三级分类，拼接成二级分类数据中的三级分类数据属性
                List<IndexCatalogVo.Catalog3Vo> level3CatalogList = level3CategoryList.stream().map(level3Category -> {
                    IndexCatalogVo.Catalog3Vo catalog3Vo = new IndexCatalogVo.Catalog3Vo(level2Category.getCatId(), level3Category.getCatId(), level3Category.getName());
                    return catalog3Vo;
                }).collect(Collectors.toList());
                indexCatalogVo.setCatalog3List(level3CatalogList);
                IndexCatalogVoList.add(indexCatalogVo);
            }
            return IndexCatalogVoList;
        }));
        return indexCatalogVoMap;
    }


    private void getFatherIds(Long cateLogId, List<Long> fatherIdList){
        Long parentCid = baseMapper.selectById(cateLogId).getParentCid();
        // 如果不等于0，说明还存在父分类
        if(parentCid != 0){
            fatherIdList.add(parentCid);
            getFatherIds(parentCid, fatherIdList);
        }
    }

    /**
     * 获取某个对象的所有子分类
     * @param categoryEntity 要被赋值的对象
     * @param categoryEntityList 用来赋值的数据集合
     */
    private List<CategoryEntity> setChildList(CategoryEntity categoryEntity, List<CategoryEntity> categoryEntityList){
        List<CategoryEntity> childList = categoryEntityList.stream().filter(category -> category.getParentCid().equals(categoryEntity.getCatId()))
                .sorted(Comparator.comparingInt(sort -> (sort.getSort() == null ? 0 : sort.getSort())))
                .peek(category -> category.setChildren(setChildList(category, categoryEntityList))).collect(Collectors.toList());
        return childList;
    }


}